///******************** NG.Respate(C)  **********************************
//* 产品名称: Respate 科技
//* 文件名称: signal.c
//* 程序作者: 雷帕特公司(南宫子萍)
//* 程序版本: V1.1														   
//* 编制日期: 2019/1/29
//* 功能描述: 系统日志
//* QQ:	2085827949
//**********************************************************************/

#include <unistd.h>
#include "stdio.h"
#include "stdlib.h"
#include "lap_lib.h"
#include "laperro.h"

#if 1
#include <signal.h>

#if 0
  标准信号的局限性：
  1. 阻塞信号可能会丢失。当一个信号阻塞时，这个信号即使多次发送给进程，也被执行一次信号句柄。
  2. 信号交付没有携带与信号有关信息。接受到信号的进程无法区分同种信号的不同情况，也不知道信号从何而来。
  3. 信号的交付没有优先级。当有多个信号悬挂与一个进程时，交付的顺序不确定。

  实时信号对标准信号做了一下扩充，有以下的特点：
  1.增加了信号从SIGRTMIN到SIGRTMAX的实时信号，可以通过sysconf(_SC_RTSIG_MAX)获得当前操作系统支持的实时信号的个数。
  2. 实时信号在队列中并按顺序交付。同一类型的实时信号将按顺序交付给进程。
  3. 实时信号可以携带额外的信息。
  4. 进程能够通过专门的函数更快的回复信号。
  5. 当定时器到期、空消息队列有消息到达、有异步IO完成时，信号能够及时交付给进程。
  ————————————————
  版权声明：本文为CSDN博主「c1194758555」的原创文章，遵循 CC 4.0 BY-SA 版权协议，转载请附上原文出处链接及本声明。
  原文链接：https://blog.csdn.net/c1194758555/article/details/52848114
#endif 

// 1.等待信号 sigsuspend
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/types.h>

// int sigsuspend(const sigset_t *mask);

void signal_handler(int sig)
{
  printf("recive signal:%s\r\n",strsignal(sig));
}

static void Lap_sigsuspend()
{
  int i =3;
  sigset_t set,set2;
  struct sigaction act;

  // 屏蔽信号
  sigemptyset(&set);
  sigaddset(&set,SIGINT);
  sigaddset(&set,SIGUSR1);
  sigprocmask(SIG_BLOCK,&set,&set2);
  
  // 捕获信号
  sigemptyset(&act.sa_mask);
  sigaddset(&act.sa_mask,SIGUSR1);
  sigaddset(&act.sa_mask,SIGINT);
  act.sa_handler = signal_handler;
  act.sa_flags = 0;
  sigaction(SIGUSR1,&act,NULL);
  sigaction(SIGINT,&act,NULL);

  while (i--)
  {
    printf("wait signal come on !\r\n");
    sigsuspend(&set2);   // 解除屏蔽并挂起系统(直到信号到来:让sigaction 能捕捉信号)
  }
}


// 
// #include "siginfo.h"
void Lapsigaction(int sig,siginfo_t *info,void *context)
{
  printf("signal [%s] info:%d pid:%d\r\n",strsignal(sig),info->si_value.sival_int,info->si_pid);
}

// 1.获取实时信号
static int Lap_sigqueue()
{
  pid_t pid = getpid();
  int ret = -1;

  struct sigaction act;
  sigemptyset(&act.sa_mask);
  sigaddset(&act.sa_mask,SIGINT);
  sigaddset(&act.sa_mask,SIGUSR1);
  act.sa_flags= SA_SIGINFO;
  act.sa_sigaction = Lapsigaction;

  ret = sigaction(SIGINT, &act,NULL);
  LAP_NegErrRet(ret,-1,"sigaction");

  ret = sigaction(SIGUSR1, &act,NULL);
  LAP_NegErrRet(ret,-1,"sigaction");
    

  union sigval val;

  val.sival_int =1;
  sigqueue(pid,SIGUSR1,val);

  val.sival_int =2;
  sigqueue(pid,SIGINT,val);

  val.sival_int =3;
  sigqueue(pid,SIGINT,val);

  val.sival_int =4;
  sigqueue(pid,SIGUSR1,val);
  usleep(1000*400);
  return 0;
}


// 同步方式等待信号
  #include <signal.h>
// int sigwaitinfo(const sigset_t *set, siginfo_t *info);
// int sigtimedwait(const sigset_t *set, siginfo_t *info,const struct timespec *timeout);
static void Lap_sigwaitinfo()
{
  pid_t pid ;
  if((pid = fork())==0) // 子线程
  {
      sigset_t set;
      siginfo_t info;

      sigfillset(&set);
      sigprocmask(SIG_SETMASK,&set,NULL);  // 阻塞所有信号

      while (1)
      {
        if(sigwaitinfo(&set,&info)<0) perror("sigwaitinfo");
        else printf("pid:%d val:%d sig:%s\r\n",info.si_pid,info.si_value.sival_int,strsignal(info.si_signo));
      }
  }else if(pid > 0){
    sleep(1);
    union sigval info;

    info.sival_int = 1;
    sigqueue(pid,SIGUSR1,info);

    info.sival_int = 2;
    sigqueue(pid,SIGUSR2,info);

    info.sival_int = 3;
    sigqueue(pid,SIGRTMIN+2,info);

    info.sival_int = 4;
    sigqueue(pid,SIGINT,info);

    info.sival_int = 5;
    sigqueue(pid,SIGRTMIN+2,info);

    info.sival_int = 6;
    sigqueue(pid,SIGHUP,info);

    sleep(4);   // 等待信号到达
    sigqueue(pid,SIGKILL,info);
    wait(NULL); // 回收子进程
  }
}



// 通过文件描述符获取信号
#include <sys/signalfd.h>
// int signalfd(int fd, const sigset_t *mask, int flags);

static void Lap_signalfd()
{
  pid_t pid;
  struct signalfd_siginfo sfd_info;
  ssize_t siginfo_size = sizeof(struct signalfd_siginfo);
  ssize_t len = -1;

  if((pid = fork())==0)
  {
    sigset_t set;

    sigfillset(&set);
    sigprocmask(SIG_SETMASK,&set,NULL);

    int sfd = signalfd(-1,&set,0);
    printf("sfd:%d\r\n",sfd);
    while (sfd>0)
    {
      len = read(sfd,&sfd_info,siginfo_size);
      if(len != siginfo_size) perror("siginfo_size eer");
      else printf("pid:%d vol:%d sig:%s\r\n",sfd_info.ssi_pid,sfd_info.ssi_int,strsignal(sfd_info.ssi_signo));
    }
  }

  // 父进程
  union sigval val;

  sleep(1);

  for (int i = 0; i <= 64; i++)
  {
    if(i==SIGKILL||i==SIGSTOP) continue;
    val.sival_int =i;
    sigqueue(pid,i,val);
    //usleep(1000*200);
  }
  for (int i = 0; i <= 64; i++)
  {
    if(i==SIGKILL||i==SIGSTOP) continue;
    val.sival_int =i;
    sigqueue(pid,i,val);
    //usleep(1000*200);
  }

  sleep(2);
  sigqueue(pid,SIGKILL,val);
  wait(NULL);
}

int main(void)
{
  LAP_ErrOutSet(NULL);  // 错误输出 初始化
  //Lap_sigsuspend();   // sigsuspend
  // Lap_sigqueue();    // 消息队列
  //Lap_sigwaitinfo();  // 
  Lap_signalfd();       // 通过文件描述符获取信号
}
#endif